package com.siteseat.common.foundation;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;



/**
 * 
 */
public abstract class ScheduledActor extends Actor {

  private ScheduledExecutorService scheduler;

  private ScheduledFuture<?>       future;

  private long                     intervalByMilliseconds;
  
  private long                     initialDelayByMilliseconds;
  
  

  /**
   * Gets the initialDelayByMilliseconds
   *
   * @return the initialDelayByMilliseconds
   */
  public long getInitialDelayByMilliseconds() {
    return initialDelayByMilliseconds;
  }

  /**
   * Sets the initialDelayByMilliseconds
   *
   * @param initialDelayByMilliseconds the initialDelayByMilliseconds to set
   */
  public void setInitialDelayByMilliseconds( long initialDelayByMilliseconds ) {
    this.initialDelayByMilliseconds = initialDelayByMilliseconds;
  }

  /**
   * Gets the intervalByMilliseconds
   * 
   * @return the intervalByMilliseconds
   */
  public long getIntervalByMilliseconds() {
    return intervalByMilliseconds;
  }

  /**
   * Sets the intervalByMilliseconds
   * 
   * @param intervalByMilliseconds
   *          the intervalByMilliseconds to set
   */
  public void setIntervalByMilliseconds( long intervalByMilliseconds ) {
    this.intervalByMilliseconds = intervalByMilliseconds;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected void doInit() throws Exception {
    // super.doInit();

    PropertyHelper.ensurePositive( log, getIntervalByMilliseconds(), "intervalByMilliseconds" );
    PropertyHelper.ensureNotNegative( log, getInitialDelayByMilliseconds(), "initialDelayByMilliseconds" );
  }
  

  /**
   * {@inheritDoc}
   */
  @Override
  protected void postInited() throws Exception {
    startScheduler();
  }
  
  
  /**
   * 
   */
  protected void startScheduler() {
    if( scheduler == null ) {
      scheduler = Executors.newSingleThreadScheduledExecutor( new SchedulerThreadFactory( getBeanName() ) );
    }
    
    future = scheduler.scheduleWithFixedDelay( this, getInitialDelayByMilliseconds(), getIntervalByMilliseconds(),
            TimeUnit.MILLISECONDS );
    
  }

  /**
   * Gets the scheduler
   * 
   * @return the scheduler
   */
  public ScheduledExecutorService getScheduler() {
    return scheduler;
  }

  /**
   * Sets the scheduler
   * 
   * @param scheduler
   *          the scheduler to set
   */
  public void setScheduler( ScheduledExecutorService scheduler ) {
    this.scheduler = scheduler;
  }

  /**
   * @throws InterruptedException
   */
  protected abstract void onScheduled() throws InterruptedException;

  /**
   * {@inheritDoc}
   */
  @Override
  protected void doRun() {
    try {
      Thread.sleep( getInitialDelayByMilliseconds() );
      while( toStop() == false ) {
        onScheduled();
        Thread.sleep( getIntervalByMilliseconds() );
      }
    } catch( InterruptedException e ) {
      log.warn( "Interrupted", e );
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected void doDestroy() throws Exception {
    if( future != null ) {
      future.cancel( false );
      future = null;
    }

    scheduler.shutdown();
    scheduler = null;
  }

}
